home *** CD-ROM | disk | FTP | other *** search
Wrap
/* * Starter for REALbasic 2.1 & 3.0 plugins * * This code shows how to add new global methods and how to create * or extend classes to RB. * Creating Controls is not shown in here - see the sample projects * in RB's plugin SDK for that. * * This code is freeware, you may use and extend it as you like. * Brought to by Thomas Tempelmann. * * The accompanying project file was created using CodeWarrior Pro 4 * with the latest updates (including IDE 3.3) from Metrowerks' FTP Site * and Universal Headers 3.3.2 as well as CarbonLib 1.2 SDK from * http://developer.apple.com/sdk/ * * More RB-related stuff and updates can be found here: * * <http://www.tempel.org/rb/> * * History: * Nov 21, 99: Initial version. * Jan 18, 2000 by TT: Verified with RB 2.1a25 that classes work * now in x86 plugins, too. * Jan 28, 2000 by TT: ("Ruslan special") Now also initializes * static C++ constructors. * Feb 1, 2000 by TT: Now also shows how to pass Boolean and * Double arguments. Also added "#pragma mpwc on" to this and to the * "PluginMain.cpp" for 68K compiles, and disabled the global MPW C * calling option in the project settings for "68K Processor". * Removed the "far" modifier from a function prototype to avoid an * error msg from the Pro 5's compiler. * Mar 4, 2000 by TT: Added a BYREF parameter example. * Jul 13, 2000 by TT: Updates for RB 2.1 - does not support * plugins for older RB versions any more. * Jan 21, 2000 by TT: Added Carbon support (requires RB 3.0) and * did a lot of other improvements. * * Enjoy and contribute! */ //-------------------- // Your includes here //-------------------- // These and other includes should come _before_ the include of "rb_plugin.h" // in order to avoid compilation errors. #include <string.h> #if TARGET_OS_WIN32 static void inline DebugStr(unsigned char* p) {} #define log(x) OutputDebugString(x) #define PrepareCallback() #define EnterCallback() #define ExitCallback() #else #if TARGET_CPU_68K #include <SetupA4.h> #endif #include <MacMemory.h> #include "dcon.h" #define log(x) dprintf(x) #endif //------------------------- // RB header includes here //------------------------- // Note: these include should come last, after all other includes of yours #include "TT's Plugin Support.h" #include "rb_plugin.h" //----------------------- // Some type definitions //----------------------- // "RBinteger" represents a RB "Integer" type: typedef long RBinteger; // "RBbool..." represent a RB "Boolean" type; you need to watch the proper use in case of making 68K plugins: typedef Boolean RBboolVar; // use this for Boolean variables stored in this plugin typedef Boolean RBboolPar; // use this to receive Boolean parameters (both by value and by reference) typedef long RBboolRet; // use this when returning a Boolean as a function result // "RBdouble" represents a RB "Double" type: #if TARGET_CPU_68K typedef Float80 RBdouble; // Attention: for this to work, "Floating Point" in the "68K Processor" options must be set to "SANE". #else typedef double RBdouble; #endif /* * Note: Passing Singles to plugin functions is currently (RB 2.1.2) not correctly supported * in RB for 68K code, so I suggest to always only use Doubles as parameters. */ //----------------------- // Add global RB methods //----------------------- static RBinteger sampleIntFunc (RBinteger a, RBinteger b) // Adds the two passed values and returns the result { return a + b; } #if TARGET_CPU_68K static void sampleDblFunc (RBdouble *result, RBdouble a, RBdouble b) { *result = a + b; } #else static RBdouble sampleDblFunc (RBdouble a, RBdouble b) { return a + b; } #endif static void sampleIRfProc (RBinteger val, RBinteger *hi, RBinteger *lo) // Splits the passed integer into a higer and a lower 16 bit value, and returns them via the two BYREF parameters { *hi = val >> 16; *lo = val & 0xFFFF; } #define copyBytes(from,to,amount) memcpy(to,from,amount) static REALstring sampleStrFunc (REALstring a, REALstring b) // Concatenates the two strings and returns the result { // get the length of the two strings long la, lb; la = a->Length(); lb = b->Length(); // create a new string object that is large enough to hold the sum of the two strings REALstring str = REALBuildString (nil, la + lb); if (str != nil) { // now copy the two strings' contents into the new string buffer copyBytes (a->CString(), (char*)str->CString(), la); copyBytes (b->CString(), (char*)str->CString() + la, lb); } return str; } static void sampleSRfProc (RBinteger n, REALstring ch, REALstring *s) // Creates a new string in "s" that multiplies the character in "ch" by "n" times. // The string is a BYREF parameter in this case. Note how the old string is // disposed first before replacing it with the new instance. { REALstring str = REALBuildString (nil, n); if (str != nil) { // fill the new string: char theChar = ch->CString()[0]; memset ((char*)str->CString(), theChar, n); // we have to dispose of the passed string since we're replacing it with a newly created one: REALUnlockString (*s); // now replace the string that was passed BYREF: *s = str; } } // For examples on handling other RB data types, such as Double and Boolean, // see the code for handling class properties further below. static REALmethodDefinition pluginMethodArray[] = { { (REALproc) sampleIntFunc, REALnoImplementation, "SampleIntFunc(A as Integer, B as Integer) as Integer" }, { (REALproc) sampleDblFunc, REALnoImplementation, "SampleDoubleFunc(A as Double, B as Double) as Double" }, { (REALproc) sampleStrFunc, REALnoImplementation, "SampleStrFunc(A as String, B as String) as String" }, { (REALproc) sampleIRfProc, REALnoImplementation, "SampleIntRefProc(val as Integer, BYREF Hi as Integer, BYREF Lo as Integer)" }, { (REALproc) sampleSRfProc, REALnoImplementation, "SampleStrRefProc(n as Integer, ch as String, BYREF s as String)" }, }; //------------------------------------------------------ // Create a new RB class or extend an existing RB class //------------------------------------------------------ // If you want to create a new class, set the following macro // to 0; // If you want to extend an existing RB class, such as FolderItem, // Date or Application, set the value to 1: #define doExtendTheClass 0 // if 0, then it'll create a new class instead extern REALclassDefinition sampleClass; // forward declaration /* * The following structure defines internal storage space for your * class. This space is not automatically visible to the user, but * only if you add property accessor routines like the ones below * (see sampleIntGetter and following). */ struct sampleClassData { // Note: If you _extend_ a class, the properties here will be zeroed, but the // constructor will not be called (Note that I have not verified that // properties get actually zeroed, this is rather what RS' documentation // says. If you find that this is not correct, don't blame me, but let me // and RS know, please.) RBinteger aInteger; RBboolVar aBoolean; // make sure that this occupies a long in case you use REALstandardGetter() or REALstandardSetter() double aDouble; }; /* * The following code implements the default constructor and destructor of the class. * * Note that those will only be called if you define a _new_ class, but not * if you extends a class (this is a bug in RB and might perhaps get fixed later). */ static void sampleClassConstructor (REALobject instance) { ClassData (sampleClass, instance, sampleClassData, me); // you can initialize objects of "me" here ... me->aInteger = 1234; } static void sampleClassDestructor (REALobject instance) { ClassData (sampleClass, instance, sampleClassData, me); // close & dispose objects of "me" here // // (e.g., if you opened a file or allocated memory, you need to release it here again) } /* * The following code shows how to deal with RB's Integer values (which is quite simple) */ static RBinteger sampleIntGetter (REALobject instance, long param) // This is called when RB reads a property of your class { ClassData (sampleClass, instance, sampleClassData, me); return me->aInteger; } static void sampleIntSetter (REALobject instance, long param, RBinteger value) // This is called when RB assigns a value to a property of your class { ClassData (sampleClass, instance, sampleClassData, me); me->aInteger = value; } /* * The following code shows how to deal with RB's Boolean values. Note that RB stores * its Boolean values as 8 bit (= 1 byte) values. However, if you return a Boolean * value from a function, you must extend it to a long (32 bit) value, or you may get * wrong results back. Using the "RBboolRet" type for function results takes care of * that for you. */ static RBboolRet sampleBoolGetter (REALobject instance, long param) // returns a boolean value as a function result { ClassData (sampleClass, instance, sampleClassData, me); return me->aBoolean != 0; // 1 is "true", 0 is "false" } static void sampleBoolSetter (REALobject instance, long param, RBboolPar value) { ClassData (sampleClass, instance, sampleClassData, me); me->aBoolean = (value != 0); } /* * The following code shows how to deal with RB's Double values - note that 68K code * needs a special handling, because in 68K a RB double is a 80 bit value, while in * PPC and x86 it is a 64 bit value: */ #if TARGET_CPU_68K static void sampleDoubleGetter (RBdouble* f, REALobject instance, long param) { ClassData (sampleClass, instance, sampleClassData, me); *f = me->aDouble; // note that here the RB's 80 bit "Float80" value is converted into C's 64 bit "double" value } #else static RBdouble sampleDoubleGetter (REALobject instance, long param) { ClassData (sampleClass, instance, sampleClassData, me); return me->aDouble; } #endif static void sampleDoubleSetter (REALobject instance, long param, RBdouble value) { ClassData (sampleClass, instance, sampleClassData, me); me->aDouble = value; // note for 68K: the 64 bit "double" value is converted into RB's 80 bit "extended" value here } /* * Here's how you can implement callbacks into the BASIC code by providing an Event Handler * in the class definition: */ typedef RBinteger (*SampleEventProc) (REALobject theObjInst, RBinteger someValue); // this is the C version of the "SampleEvent" declaration below, but with an added obj reference parm static REALevent sampleClassEvents[] = { // defines events, which is where the plugin can call back into the high-level RB application code: { "SampleEvent(someValue as Integer) as Integer" }, }; static RBinteger callSampleEvent (REALobject instance, RBinteger firstArgument) // Use a routine like this if you wish to call back into BASIC code through an Event Handler. // The "instance" parameter receives the object that contains the Event Handler definition. // The "firstArgument" parm gets passed to the Event Handler. // This function then returns the result from the Event call, or returns 0 if there's no Event Handler implemented { RBinteger result; int idx = 0; // this index selects from the sampleClassEvents array. 0 is the first entry. SampleEventProc fp = (SampleEventProc) REALGetEventInstance ((REALcontrolInstance)instance, &sampleClassEvents[idx]); if (fp) { // now call into the BASIC code result = fp (instance, firstArgument); } else { // if fp is nil, then no code BASIC has been filled in for SampleEvent. No need to call it then, of course. result = 0; } return result; } /* * The following code shows how to implement methods of a class */ static void sampleClassMethod (REALobject instance, RBinteger aValue) // This is called when RB calls a method of your class // As a demonstration, this function calls then back into BASIC code through the "SampleEvent" Event Handler { ClassData (sampleClass, instance, sampleClassData, me); me->aInteger = callSampleEvent (instance, aValue); } static void sampleBoolRefGetter (REALobject instance, RBboolPar *value) // returns a boolean value via a BYREF parameter { ClassData (sampleClass, instance, sampleClassData, me); *value = me->aBoolean; } /* * The following structures declare the class and its members */ static REALproperty sampleClassProperties[] = { // defines a property "SampleInt as Integer" (also see note below!): { nil, "SampleInt", "Integer", 0, (REALproc) sampleIntGetter, (REALproc) sampleIntSetter, 0 /* param */ }, { nil, "SampleDouble", "Double", 0, (REALproc) sampleDoubleGetter, (REALproc) sampleDoubleSetter, 0 /* param */ }, { nil, "SampleActiveBool", "Boolean", 0, (REALproc) sampleBoolGetter, (REALproc) sampleBoolSetter, 0 /* param */ }, { nil, "SamplePassiveBool", "Boolean", 0, REALstandardGetter, REALstandardSetter, FieldOffset(sampleClassData, aBoolean) }, }; // Note about the above SampleActiveBool and SamplePassiveBool properties: // If you do not need control over the events when your properties get read or set, you can use // a simpler way that what's shown above in many cases: Instead of providing your own Getter/Setter // functions, you can let RB handle the access to your properties, provided they have matching // size. The SamplePassiveBool uses this alternate way, accessing the _same_ property of this object. static REALmethodDefinition sampleClassMethods[] = { // defines methods: { (REALproc) sampleBoolRefGetter, REALnoImplementation, "SampleGetBool(ByRef b as Boolean)"}, { (REALproc) sampleClassMethod, REALnoImplementation, "SampleMethod(aValue as Integer)"}, }; static REALclassDefinition sampleClass = { kCurrentREALControlVersion, #if doExtendTheClass "aRBClassName", // <- put the name of the to be extended class here, like "FolderItem" nil, #else "SampleClass", // <- this is the name of the class you're adding with this plugin nil, // <- name of its super class, in case this is not a base class #endif sizeof(sampleClassData), 0, #if doExtendTheClass // Unfortunately, for extended classes, we don't get called when an obj is con-/destructed. // (this is a current RB restriction and might be changed in a later version, hopefully) nil, nil, #else (REALproc) sampleClassConstructor, (REALproc) sampleClassDestructor, #endif sampleClassProperties, sizeof(sampleClassProperties) / sizeof(REALproperty), sampleClassMethods, sizeof(sampleClassMethods) / sizeof(REALmethodDefinition), sampleClassEvents, sizeof(sampleClassEvents) / sizeof(REALevent), nil, 0 }; // --------------------------------- // ----- Plugin Initialization ----- // --------------------------------- /* * The following two functions get called when the app, that used this plugin, * starts up ("PluginInit") and when it quits ("PluginExit"). */ void PluginInit (void) { /* * You can init global data here, like installing a Timer Task. * Note that this function gets called before PluginEntry (). */ //log ("[TT's Plugin Starter] PluginInit called\n"); } void PluginExit (void) { /* * You can do your cleanup here in case you did open persistent resources * (like having a Timer Task or asynchronous functions pending). */ //log ("[TT's Plugin Starter] PluginExit called\n"); } void PluginEntry (void) { InitTTsPluginSupport (); /* * This is the main entry that is called when your plugin is loaded by REALbasic * or when a built application that uses your plugin is launched. * * Here you tell RB about what your plugin provides. Call ... * • REALRegisterMethod() to add gobal methods * • REALRegisterClass() to add new classes * • REALRegisterClassExtension() to extent existing classes * • REALRegisterControl() to add new controls */ //log ("[TT's Plugin Starter] PluginEntry called\n"); /* * Prepare for potential callbacks. * Explanation: If you have functions that are being called by Mac OS, * such as async completion routines and timers, you need to call EnterCallback() * at their beginning and ExitCallback() before returning from them. * Otherwise, you may get crashes in 68K code. If you do not make a 68K plugin, you * do not need to take care of this, however. See TT's EventMonitor for a complete * example. */ #if TARGET_CPU_68K PrepareCallback (); #endif // Use this code to make any of your class definitions known to RB: #if doExtendTheClass REALRegisterClassExtension (&sampleClass); #else REALRegisterClass (&sampleClass); #endif // Use this code to make your global RB methods known to RB: for (int i = 0; i < sizeof(pluginMethodArray) / sizeof(REALmethodDefinition); ++i) { REALRegisterMethod (&pluginMethodArray[i]); } //log ("[TT's Plugin Starter] PluginEntry done.\n"); }